
import { _decorator, Component, Node, UITransform, Widget } from 'cc';
import { RandomPseudo } from '../../../../extensions/cocos-scaffold-3x/assets/common/RandomPseudo';
import { LoggerManager } from '../../../../extensions/cocos-scaffold-3x/assets/manger/LoggerManager';
import { NodePoolMap } from '../../../../extensions/cocos-scaffold-3x/assets/ui/NodePoolMap';
import { EBundleName, gg } from '../../../Game';
import { GameplayComponent } from '../GameplayComponent';
import ViewGameplay from '../ViewGameplay';
import { Comp } from '../m/CompDef';
import { HeroActionEventData, GpLogicDef } from '../m/GpDef';
import { GpEventDef } from '../m/GpEventDef';
import { Sglt } from '../m/SgltDefine';
import { DamageEventInfo } from '../m/systems/battle/BattleSystem';
import GpBuilding from './GpBulding';
import { GpEntity, GpEntityProp } from './GpEntity';
import GpHero from './GpHero';
import GpLockBullet from './GpLockBullet';
import GpMaker, { GpMakerProp, MakeConfig } from './maker/GpMaker';
import { EcsEntity } from 'ecs-ts';
import { AudioManager } from '../../../common/AudioManager';
const { ccclass, property } = _decorator;

export enum GpWorldLayer {
    bottom,
    shadow,
    unit,
    buff,
    bullet,
    damageLabel,
    top,
}
@ccclass
export default class GpWorld extends GameplayComponent<ViewGameplay> {
    random: RandomPseudo = new RandomPseudo(123)
    /**高度除数 */
    heightDiv = 2
    /**宽度除数 */
    widthDiv = 2
    /**宽度除数 */
    viewPortWidth = 0
    /**宽度除数 */
    viewPortHeight = 0

    /**遮挡剔除宽度 */
    cullingWidth = 0
    /**遮挡剔除宽度平方 */
    cullingWidthPow = 0
    /**遮挡剔除高度 */
    cullingHeight = 0
    /**遮挡剔除高度平方 */
    cullingHeightPow = 0

    entityMap: Map<number, GpEntity> = new Map();

    @property(Node)
    entityLayer: Node = null!;

    @property(Node)
    hudLayer: Node = null!;

    onInit(): void {
        const ecsWorld = this.prop.ecsWorld
        this.node.getComponent(GpMaker).init(
            new GpMakerProp(this, [
                new MakeConfig(
                    ecsWorld.getGroupByClz(Comp.Hero),
                    (ecsEntity) => { return !!ecsEntity.component(Comp.Hero) },
                    (ecsEntity) => { return "gameplay/v/GpHero" },
                    (gpEntity) => { gpEntity.node.getComponent(GpHero).init(null) },
                    GpWorldLayer.unit,
                    new NodePoolMap(GpHero, EBundleName.subBundle),
                ),
                new MakeConfig(
                    ecsWorld.getGroupByClz(Comp.Battle.Bullet),
                    (ecsEntity) => { return !!ecsEntity.component(Comp.Battle.Bullet) },
                    (ecsEntity) => { return "gameplay/v/GpLockBullet" },
                    (gpEntity) => { gpEntity.node.getComponent(GpLockBullet).init(null) },
                    GpWorldLayer.unit,
                    new NodePoolMap(GpLockBullet, EBundleName.subBundle),
                ),
                new MakeConfig(
                    ecsWorld.getGroupByClz(Comp.Bulding),
                    (ecsEntity) => { return !!ecsEntity.component(Comp.Bulding) },
                    (ecsEntity) => { return "gameplay/v/GpBuilding" },
                    (gpEntity) => { gpEntity.node.getComponent(GpBuilding).init(null) },
                    GpWorldLayer.bottom,
                    new NodePoolMap(GpBuilding, EBundleName.subBundle),
                )

            ])
        )
        this.calculateCullingData()
        const worldInfo = ecsWorld.getSingleton(Sglt.WorldInfo)

        this.node.getComponent(UITransform).setContentSize(worldInfo.width, worldInfo.height)

        // this.node.parent.setContentSize(worldInfo.width, worldInfo.height)
        this.node.parent.getComponent(Widget).updateAlignment()
        this.initEventHandle()
    }

    initEventHandle() {

        gg.eventTarget.on(GpEventDef.onActionStart, (data: HeroActionEventData) => {
            const gpEntity = this.entityMap.get(data.entity.id)
            gpEntity && gpEntity.getComponent(GpHero).onActionStart(data)
        }, this)
        gg.eventTarget.on(GpEventDef.onActionEnd, (data: HeroActionEventData) => {
            const gpEntity = this.entityMap.get(data.entity.id)
            gpEntity && gpEntity.getComponent(GpHero).onActionEnd(data)
        }, this)
        gg.eventTarget.on(GpEventDef.onAttPointTriggered, (entity: EcsEntity, battleInfo: Comp.Battle.BattleInfo, target: EcsEntity, targetBattleInfo: Comp.Battle.BattleInfo) => {
            const gpEntity = this.entityMap.get(entity.id)
            gpEntity && gpEntity.getComponent(GpHero).onAttPointTriggered(entity, battleInfo, target, targetBattleInfo)
        }, this)
        gg.eventTarget.on(GpEventDef.onDamage, (eventInfo: DamageEventInfo) => {
            if (eventInfo.target.id == 10000) {
                return
            }
            const gpEntity = this.entityMap.get(eventInfo.target.id)
            gpEntity && gpEntity.getComponent(GpHero).onDamage(eventInfo)
        }, this)
        gg.eventTarget.on(GpEventDef.playSound, (data: GpLogicDef.PlaySoundData) => {
            AudioManager.instance().playEffect(this.random.randomElementFromList(data.sounds))
        }, this)
    }

    calculateCullingData() {
        this.viewPortWidth = this.node.parent.getComponent(UITransform).width
        this.viewPortHeight = this.node.parent.getComponent(UITransform).height
        this.cullingWidth = (this.viewPortWidth / this.widthDiv) / this.node.scale.x
        this.cullingWidthPow = this.cullingWidth * this.cullingWidth
        this.cullingHeight = (this.viewPortHeight / this.heightDiv) / this.node.scale.x
        this.cullingHeightPow = this.cullingHeight * this.cullingHeight
    }

    onLoad(): void {
        for (let i = 0; i <= GpWorldLayer.top; i++) {
            const layer = new Node()
            layer.addComponent(UITransform)
            this.entityLayer.addChild(layer)
        }
    }

    removeMapEntity(ecsEntityId) {
        if (this.entityMap.has(ecsEntityId)) {
            this.entityMap.delete(ecsEntityId)
        }
    }

    /**添加实体 */
    addEntity(entity: GpEntity, ecsEntity: EcsEntity, layer: GpWorldLayer = GpWorldLayer.bottom): GpEntity {
        if (this.entityMap.get(ecsEntity.id)) {
            LoggerManager.instance().log('entity exist', entity);
            return
        }
        entity.init(new GpEntityProp(this, this.prop.ecsWorld, ecsEntity.id))
        this.entityMap.set(ecsEntity.id, entity)
        this.addNodeOnLayer(entity.node, layer)
        return entity
    }

    /**添加节点到某一层
    * @param node 要添加的节点
    * @param layer 层级
    * @param layerNode 指定某个节点作为层级节点
    */
    addNodeOnLayer(node: Node, layer: GpWorldLayer | Node) {
        let layerNode: Node = layer as any
        if (typeof layer != "object") {
            layerNode = this.entityLayer.children[layer]
        }
        if (node.parent != layerNode) {
            node.parent = layerNode
        } else {
            node.active = true
        }
    }

    /**获取某一层的节点 */
    getLayer(layer: GpWorldLayer) {
        return this.entityLayer.children[layer]
    }

    protected update(dt: number): void {
        this.calculateCullingData()
    }
    /**更新所有实体的位置 */
    updateAllEntityTransform() {
        const nodeScale = this.node.scale.x

        const x = (this.node.position.x * -1) / nodeScale
        const y = (this.node.position.y * -1) / nodeScale
        this.cullingWidthPow = ((this.cullingWidth / nodeScale) ** 2)
        this.cullingHeightPow = ((this.cullingHeight / nodeScale) ** 2)

        /**y轴缩放，用来模拟场景的倾斜视差 */
        const yScale = 1

        this.entityMap.forEach((entity, ecsEntityId) => {

            const transform = entity.transform

            const entityNode = entity.node
 
            // const isOutOfView = Math.abs(x - transform.pos.x) > this.cullingWidth + transform.radius && Math.abs(x - entity.node.position.x) > this.cullingWidth || Math.abs(y - transform.pos.y) * yScale > this.cullingHeight && Math.abs(y - entity.node.position.y) > this.cullingHeight + transform.radius;
            // (entityNode.active = true || !isOutOfView);
            // // !isOutOfScreen && (entity.updateTransform(transform));
            // if (!isOutOfView) {
            //     entityNode.setPosition(transform.pos.x, transform.pos.y * yScale)
            // }

            
            entityNode.setPosition(transform.pos.x, transform.pos.y * yScale)
            

        })
        this.updateAllEntityIndex()
    }

    updateAllEntityIndex() {
        const children=this.getLayer(GpWorldLayer.unit).children.slice().sort((a, b) => b.position.y - a.position.y)
        for (let index = 0; index < children.length; index++) {
            const child = children[index];
            child.setSiblingIndex(index)
            
        }
    }

    protected onDestroy(): void {
        gg.eventTarget.targetOff(this)
    }




    addDamageLabel(eventInfo: DamageEventInfo) {

    }

} 